/*CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
 C	sc2sim.c
 C	Application Name: SC-2 (lite) simulation
 C	Programmers Names:
 C	Date Completed: 3/9/11
 C	Brief Description: Source file for the sc2sim application.  This application simulates a
 C	subset of the SC-2's ISA.  It uses the register, register file, and ALU ADT's that we've
 C	developed so far to simulate the CPU's physical components.
 C
 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC*/

#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>

#include "Sc2sim.h"

//the below are needed to avoid multiple file compilation
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 + Register16 ADT implementation
 +
 + Basic operations
 +      Initialize: creates register object and puts a random value from 0 to 65535 into it.
 +      GetLowByte: returns an unsigned char (uchar) from LOB of register
 +      GetHIByte: returns a uchar from the HOB of register
 +      PutLowByte: puts a uchar into the LOB of the register
 +      PutHIByte: puts a uchar into the HOB of the register
 +      SignOf: returns bit 15 value in a uchar
 +      Destructor: not needed
 + Composite Operations
 +      GetRegValue: returns a ushort, the value in the register
 +      PutRegValue: returns error, puts ushort into register
 +
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*=================================================================================================
 = Comment block for function: register_initialize
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      RegisterPtr register_initialize(void)
 =      Return value ranges: Initialized pointer to register
 =      Parameter value ranges: N/a
 =      Error conditions: N/a
 = Initializes a RegisterPtr to a random value.
 ==================================================================================================*/
RegisterPtr register_initialize(void) {
    RegisterPtr rp = (RegisterPtr) malloc(sizeof(ushort));
    if (rp != NULL)
    {
        * rp = rand() * ((double)MAX_USHORT / (double)RAND_MAX);
    }
    return rp;
}

/*=================================================================================================
 = Comment block for function: register_getLowByte
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      uchar register_getLowByte(RegisterPtr rp, int * error)
 =      Return value ranges: A uchar containing the low order byte of the Register pointed at by rp
 =      Parameter value ranges: Pointer to a Register, pointer to an integer
 =      Error conditions: rp is null pointer
 = Retrieves the low order byte of the Register being pointed at by a RegisterPtr.
 ==================================================================================================*/
uchar register_getLowByte(RegisterPtr rp, int * error) {
        if (rp == NULL) {
                *error |= NULL_ERR;
                return 0;
        }
        return *rp & LOB_MASK;
}

/*=================================================================================================
 = Comment block for function: register_getHiByte
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      uchar register_getHiByte(RegisterPtr rp, int * error)
 =      Return value ranges: A uchar containing the high order byte of the Register pointed at by rp
 =      Parameter value ranges: Pointer to a register, pointer to an integer
 =      Error conditions: rp is a null pointer
 = Retrieves the high order byte of the Register being pointed at by a RegisterPtr.
 ==================================================================================================*/
uchar register_getHiByte(RegisterPtr rp, int * error) {
        if (rp == NULL) {
                *error |= NULL_ERR;
                return 0;
        }
        return *rp >> 8; //since were casting down the data we want to keep needs to be in the rightmost byte
}

/*=================================================================================================
 = Comment block for function: register_putLowByte
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int register_putLowByte(RegisterPtr rp, uchar byte)
 =      Return value ranges: Error code: 0 (success) or NULL_ERR
 =      Parameter value ranges: Pointer to a register, data you wish to insert (0 -> 2^8-1)
 =      Error conditions: rp is a null pointer
 = Puts a byte of data into the low order byte of a Register being pointed at by a RegisterPtr.
 ==================================================================================================*/
int register_putLowByte(RegisterPtr rp, uchar byte) {
        if (rp == NULL)
                return NULL_ERR;
        Register result = *rp;
        result = result & HOB_MASK; //clear out the low order byte of whats already there
        result = result | byte; //now put our value in there with a bitwise or
        *rp = result;
        return 0; //success!
}

/*=================================================================================================
 = Comment block for function: register_putHiByte
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int register_putHiByte(RegisterPtr rp, uchar byte)
 =      Return value ranges: Error code: 0 (success) or NULL_ERR
 =      Parameter value ranges: Pointer to register, data you wish to insert (0 -> 2^8-1)
 =      Error conditions: rp is a null pointer
 = Puts a byte of data into the high order byte of a Register being pointed at by a RegisterPtr.
 ==================================================================================================*/
int register_putHiByte(RegisterPtr rp, uchar byte) {
        if (rp == NULL)
                return NULL_ERR;
        Register result = *rp;
        ushort temp = byte << 8; //to use this ORing method, the data needs to be in the leftmost byte (hope gcc fills shifts with zeros :D)
        result = result & LOB_MASK; //clear high order byte
        result = result | temp; //or value in
        *rp = result;
        return 0; //success
}

/*=================================================================================================
 = Comment block for function: register_signOf
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      uchar register_signOf(RegisterPtr rp)
 =      Return value ranges: 0 if the data is positive, 1 if it is negative, or NULL_ERR
 =      Parameter value ranges: Pointer to a register
 =      Error conditions: rp is a null pointer
 = Determines the sign of the data held in a Register being pointed at by a RegisterPtr.
 ==================================================================================================*/
uchar register_signOf(RegisterPtr rp) {
        if (rp == NULL)
                return NULL_ERR;
        return *rp & BIT_15 ? 1 : 0;
        //if *rp & BIT_15 is greater than 0 than the 15th bit must be set so we return 1, otherwise return zero
}

/*=================================================================================================
 = Comment block for function: register_getRegValue
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      ushort register_getRegValue(RegisterPtr rp, int * error)
 =      Return value ranges: The data held in the Register pointed at by rp (16 bits)
 =      Parameter value ranges: Pointer to a register, pointer to an int
 =      Error conditions: rp is a null pointer
 = Retrieves all 16 bits of data from a Register being pointed at by a RegisterPtr.
 ==================================================================================================*/
ushort register_getRegValue(RegisterPtr rp, int * error) {
        if (rp == NULL) {
                *error |= NULL_ERR;
                return 0;
        }
        ushort result = *rp;
        return result;
}

/*=================================================================================================
 = Comment block for function: register_putRegValue
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int register_puteRegValue(RegisterPtr rp, ushort word)
 =      Return value ranges: Error code: 0 (success) or NULL_ERR
 =      Parameter value ranges: Pointer to register, data to be put in register (0 -> 2^16)
 =      Error conditions: rp is a null pointer
 = Puts a full word of data into a Register being pointed at by RegisterPtr.
 ==================================================================================================*/
int register_putRegValue(RegisterPtr rp, ushort word) {
        if (rp == NULL) {
                return NULL_ERR;
        }
        *rp = word;
        return 0;
}



/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 + SC-2 RegisterFile
 + Basic Operations:
 +      Initialize: 	creates a register file of 16 register objects in an array
 +      GetByteFrom: 	returns a uchar from a designated register and LOB or HOB
 +      PutByteTo: 	puts a single byte to either LOB or HOB or register
 + Composite Operations:
 +      GetWordFrom: 	returns a ushort, the content of the designated register
 +      PutWordTo: 	puts the ushort into the designated register
 +
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*=================================================================================================
 = Comment block for function: registerFile_initialize
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      RegisterFilePtr registerFile_initialize()
 =      Return value ranges: Pointer to the created register file
 =      Parameter value ranges: N/A
 =      Error conditions: N/A
 = Initializes and returns a RegisterFilePtr to a random value.
 ==================================================================================================*/
RegisterFilePtr registerFile_initialize() {
        RegisterFilePtr rfptr = (RegisterFilePtr) malloc(sizeof(RegisterPtr) * REGISTER_COUNT);
        int i = 0;
        for (i; i < REGISTER_COUNT; i++) {
                rfptr[i] = (RegisterPtr) register_initialize();
        }
        return rfptr;
}

/*=================================================================================================
 = Comment block for function: registerFile_getByteFrom
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      uchar registerFIle_getByteFrom(RegisterFilePtr rf, uchar reg_num, uchar which, int * error)
 =      Return value ranges: Uchar (8 bits) of data that was contained in the specified register
 =      Parameter value ranges: Pointer to register, numerical name of the register (0-15), LOB_WHICH or HOB_WHICH, pointer to an int
 =      Error conditions: rf is a null pointer, reg_num is out of range
 = Retrieves a single byte from a Register, either the high order byte or low order byte, as specified by the parameter.
 ==================================================================================================*/
uchar registerFile_getByteFrom(RegisterFilePtr rf, uchar reg_num, uchar which, int * error) {
        if (rf == NULL) {
                *error |= NULL_ERR;
                return 0;
        }
        if (reg_num > REGISTER_COUNT - 1) {
                *error |= REG_NOT_FOUND_ERR;
                return 0;
        }
        RegisterPtr regptr = rf[reg_num];
        switch (which) {
                case LOB_WHICH: {
                        return register_getLowByte(regptr, error);
                        break;
                }
                case HOB_WHICH: {
                        return register_getHiByte(regptr, error);
                        break;
                }
                default: {
                        break;
                }
        }
        return 0; //shouldn't ever get here...
}

/*=================================================================================================
 = Comment block for function: registerFile_putByteTo
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int registerFile_putByteTo(RegisterFilePtr rf, uchar reg_num, uchar which, uchar byte)
 =      Return value ranges: Error code: 0 (success), NULL_ERR, REG_NOT_FOUND_ERR
 =      Parameter value ranges: Pointer to register, numerical name of the register(0-15), LOB_WHICH or HOB_WHICH, data to be put in register (0 -> 2^16)
 =      Error conditions: rf is a null pointer, reg_num is out of range
 = Puts a byte of data to the specifiec Register in the RegisterFile.
 ==================================================================================================*/
int registerFile_putByteTo(RegisterFilePtr rf, uchar reg_num, uchar which, uchar byte) {
        if (rf == NULL)
                return NULL_ERR;
        if (reg_num > REGISTER_COUNT - 1)
                return REG_NOT_FOUND_ERR;
        RegisterPtr regptr = rf[reg_num];
        switch(which) {
                case LOB_WHICH: {
                        return register_putLowByte(regptr, byte);
                        break;
                }
                case HOB_WHICH: {
                        return register_putHiByte(regptr, byte);
                        break;
                }
                default: {
                        break;
                }
        }
        return 0; //shouldn't ever get here
}

/*=================================================================================================
 = Comment block for function: registerFile_getRegValue
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      ushort registerFile_getRegValue(RegisterFilePtr rf, uchar reg_num, int * error)
 =      Return value ranges: A ushort (16 bits) of data that was contained in the specified Register
 =      Parameter value ranges: Pointer to register, numerical name of the register (0-15), a pointer to an int
 =      Error conditions: rf is a null pointer, reg_num is out of range
 = Retrieves the entire contents of a specified Register.
 ==================================================================================================*/
ushort registerFile_getRegValue(RegisterFilePtr rf, uchar reg_num, int * error) {
        if (rf == NULL) {
                *error |= NULL_ERR;
                return 0;
        }
        if (reg_num > REGISTER_COUNT - 1) {
                *error |= REG_NOT_FOUND_ERR;
                return 0;
        }
        RegisterPtr regptr = rf[reg_num];
        return register_getRegValue(regptr, error);
}

/*=================================================================================================
 = Comment block for function: registerFile_putRegValue
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int registerFile_putRegValue(RegisterFilePtr rf, uchar reg_num, ushort value)
 =      Return value ranges: Error code: 0 (success), NULL_ERR, or REG_NOT_FOUND_ERR
 =      Parameter value ranges: Pointer to register, numerical name of the register (0-15), data to be put in register (0 -> 2^16)
 =      Error conditions: rf is a null pointer, reg_num is out of range
 = Puts 16 bits of data into a specified Register.
 ==================================================================================================*/
int registerFile_putRegValue(RegisterFilePtr rf, uchar reg_num, ushort value) {
        if (rf == NULL)
                return NULL_ERR;
        if (reg_num > REGISTER_COUNT - 1)
                return REG_NOT_FOUND_ERR;
        RegisterPtr regptr = rf[reg_num];
        return register_putRegValue(regptr, value);
}


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 + SC-2 Internal Registers
 + Basic Operations:
 +		Initialize:  Creates Internal Registers object
 +      Set Halt: Sets the halt bit to the specified value (TRUE or FALSE).
 +      Check Halt: Returns the current value of the halt bit.
 +
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/*=================================================================================================
 = Comment block for function: internalRegisters_initialize()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      InternalRegisters internalRegisters_initialize();
 =      Return value ranges: Internal Registers pointer
 =      Parameter value ranges: N/A
 =      Error conditions: N/A
 = Allocates memory and returns a pointer to the Internal Registers struct.
 ==================================================================================================*/
InternalRegisters internalRegisters_initialize()
{
	InternalRegisters internal = (InternalRegisters) malloc(sizeof(InternalRegistersStr));

	internal->pc = register_initialize();
	internal->ir = register_initialize();
	internal->sw = register_initialize();

	internal->halt_bit = FALSE;

	return internal;
}

/*=================================================================================================
 = Comment block for function: internalRegisters_setPC
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int internalRegisters_setPC(InternalRegisters the_internal, ushort the_address)
 =      Return value ranges: Error code: 0 (success) or NULL_ERR
 =      Parameter value ranges: Pointer to Internal Registers, address to be put in PC (0 -> 2^16)
 =      Error conditions: the_internal is a null pointer
 = Sets the address contained in the PC register.
 ==================================================================================================*/
int internalRegisters_setPC(InternalRegisters the_internal, ushort the_address)
{
    int error = 0;
    if (the_internal != NULL)
    {
        error |= register_putRegValue(the_internal->pc, the_address);
    }
    else
    {
        error |= NULL_ERR;
    }

    return error;
}

/*=====================================================================================================
=   Comment block for function: internalRegisters_getPC
=   Programmer name:
=   Final test and approval date:
=   Synopsis:
=                ushort internalRegisters_getPC(InternalRegisters the_internal, int * the_error);
=                return value ranges: 0 to 0xFFFF. Note will return 0 on any error.
=                parameter value ranges: the_internal and the_error are valid pointers.
=                error conditions: NULL_ERR if the_internal is null.
=
=   Returns the current value of the PC register.
====================================================================================================*/
ushort internalRegisters_getPC(InternalRegisters the_internal, int * the_error)
{
    ushort reg_value = 0;
    if (the_internal != NULL)
    {
        reg_value = register_getRegValue(the_internal->pc, the_error);
    }
    else
    {
        * the_error |= NULL_ERR;
    }

    return reg_value;
}

/*=================================================================================================
 = Comment block for function: internalRegisters_setIR
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int internalRegisters_setIR(InternalRegisters the_internal, ushort the_instruction)
 =      Return value ranges: Error code: 0 (success) or NULL_ERR
 =      Parameter value ranges: Pointer to Internal Registers, instruction word (0 -> 2^16)
 =      Error conditions: the_internal is a null pointer
 = Sets the instruction word contained in the IR register.
 ==================================================================================================*/
int internalRegisters_setIR(InternalRegisters the_internal, ushort the_instruction)
{
    int error = 0;
    if (the_internal != NULL)
    {
        error |= register_putRegValue(the_internal->ir, the_instruction);
    }
    else
    {
        error |= NULL_ERR;
    }

    return error;
}

/*=====================================================================================================
=   Comment block for function: internalRegisters_getIR
=   Programmer name:
=   Final test and approval date:
=   Synopsis:
=                ushort internalRegisters_getIR(InternalRegisters the_internal, int * the_error);
=                return value ranges: 0 to 0xFFFF. Note will return 0 on any error.
=                parameter value ranges: the_internal and the_error are valid pointers.
=                error conditions: NULL_ERR if the_internal is null.
=
=   Returns the current value of the IR register.
====================================================================================================*/
ushort internalRegisters_getIR(InternalRegisters the_internal, int * the_error)
{
    ushort reg_value = 0;
    if (the_internal != NULL)
    {
        reg_value = register_getRegValue(the_internal->ir, the_error);
    }
    else
    {
        * the_error |= NULL_ERR;
    }

    return reg_value;
}

/*=================================================================================================
 = Comment block for function: internalRegisters_setSW
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int internalRegisters_setSW(InternalRegisters the_internal, ushort the_status)
 =      Return value ranges: Error code: 0 (success) or NULL_ERR
 =      Parameter value ranges: Pointer to Internal Registers, status word (0 -> 2^16)
 =      Error conditions: the_internal is a null pointer
 = Sets the status word contained in the SW register.
 ==================================================================================================*/
int internalRegisters_setSW(InternalRegisters the_internal, ushort the_status)
{
    int error = 0;
    if (the_internal != NULL)
    {
        error |= register_putRegValue(the_internal->pc, the_status);
    }
    else
    {
        error |= NULL_ERR;
    }

    return error;
}

/*=====================================================================================================
=   Comment block for function: internalRegisters_getSW
=   Programmer name:
=   Final test and approval date:
=   Synopsis:
=                ushort internalRegisters_getSW(InternalRegisters the_internal, int * the_error);
=                return value ranges: 0 to 0xFFFF. Note will return 0 on any error.
=                parameter value ranges: the_internal and the_error are valid pointers.
=                error conditions: NULL_ERR if the_internal is null.
=
=   Returns the current value of the SW register.
====================================================================================================*/
ushort internalRegisters_getSW(InternalRegisters the_internal, int * the_error)
{
    ushort reg_value = 0;
    if (the_internal != NULL)
    {
        reg_value = register_getRegValue(the_internal->sw, the_error);
    }
    else
    {
        * the_error |= NULL_ERR;
    }

    return reg_value;
}

/*=====================================================================================================
 =   	Comment block for function: internalRegisters_setHalt()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int internalRegisters_setHalt(InternalRegisters the_internal, BOOLEAN the_value)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointer to Internal Registers, BOOLEAN value (TRUE or FALSE).
 =	error conditions:  	null pointer
 =
 =	Sets the halt bit to TRUE or FALSE.
 =  Note: Any input besides FALSE will set the bit to "true".
 =
 ====================================================================================================*/
int internalRegisters_setHalt(InternalRegisters the_internal, BOOLEAN the_value)
{
	int error = 0;
	if(the_internal != NULL)
	{
		the_internal->halt_bit = the_value;
	}
	else
	{
		error |= NULL_ERR;
	}

	return error;
}


/*=====================================================================================================
 =   	Comment block for function: internalRegisters_checkHalt()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		BOOLEAN internalRegisters_checkHalt(InternalRegisters the_internal, int * the_error)
 =	return value ranges: 	BOOLEAN TRUE or FALSE
 =	parameter value ranges: pointer to Internal Registers, pointer to error code.
 =	error conditions:  	null pointer
 =
 =	returns value of halt bit - be sure to check for
 =
 ====================================================================================================*/
BOOLEAN internalRegisters_checkHalt(InternalRegisters the_internal, int* the_error)
{
	BOOLEAN value;
	if(the_internal != NULL)
	{
		value = the_internal->halt_bit;
	}
	else
	{
		* the_error |= NULL_ERR;
	}

	return value;
}


 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 + SC-2 ALU
 + Basic Operations:
 +		Initialize:  Creates ALU object
 +		Execute:   Simulates a clock signal, causing the selected operation to execute.
 +
 +	'External' Operations
 +		Load A:  	Simulates the state of the A register as LdA is
 +				enabled by explicitly loading an operand into A
 +
 +		Load B:  	Simulates the state of the B register as LdB is
 +				enabled by explicitly loading an operand into B
 +
 +		Select Operation:  	Simulates the op_sel signal by loading a
 +					value into the op_sel register
 +
 +		Set Status:  	Sets the relevant bit in SW
 +
 +		Read Output C:  Simulates the state of the data bus as DrALU is
 +				enabled by explicitly reading the value of C
 +
 +	'Internal' Operations:
 +		Addition:  	C <- A + B, set status
 +		Subtraction:  	C <- A - B, set status
 +		Multiplication: $R8 <- (low-order) A * B, set status
 +				$R9 <- (high-order) A * B, set status
 +		Division: 	$RA <- (quotient) A / B, set status
 +				$RB <- (remainder) A / B, set status
 +		Negation:  	C <- ~A + 1 (2's complement), set status
 +		AND:		C <- A & B, set status
 +		OR:		C <- A | B, set status
 +		XOR:		C <- A ^ B (bitwise XOR), set status
 +		NOT:		C <- ~A, set status
 +		Shift Left:	C <- A * 2, set status
 +		Shift Right: 	C <- A / 2, set status
 +
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
// EXTERNAL FUNCTIONS - functions that simulate the ALU's interface with the rest of the CPU

/*=================================================================================================
 = Comment block for function: ALU_initialize()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      ALU ALU_initialize();
 =      Return value ranges: address pointer
 =      Parameter value ranges: N/A
 =      Error conditions: N/A
 = Allocates memory and returns a pointer to the ALU struct.
 ==================================================================================================*/
ALU ALU_initialize()
{
	ALU alu = (ALU) malloc(sizeof(ALUStr));

	alu->A = register_initialize();
	alu->B = register_initialize();
	alu->C = register_initialize();
	alu->op_sel = 0;

	return alu;
}

/*=================================================================================================
 = Comment block for function: ALU_execute()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int ALU_execute(ALU, RegisterFilePtr, RegisterPtr);
 =      Return value ranges: 0 (success), NULL_ERR
 =      Parameter value ranges: pointers to ALU, CPU registerfile, SW register
 =      Error conditions: Null pointers
 = Simulates a clock signal, causing the selected operation to execute.
 ==================================================================================================*/
int ALU_execute(ALU aa, RegisterFilePtr rf, RegisterPtr sw)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL && rf != NULL && sw != NULL && error != NULL)
	{
		// switch to select internal operation
		switch(aa->op_sel)
		{
			case OP_ADD:
				err = ALU_add(aa);
				break;
			case OP_SUB:
				err = ALU_sub(aa);
				break;
			case OP_MUL:
				err = ALU_multiply(aa, rf);
				break;
			case OP_DIV:
				err = ALU_divide(aa, rf);
				break;
			case OP_NEG:
				err = ALU_negate(aa);
				break;
			case OP_AND:
				err = ALU_and(aa);
				break;
			case OP_OR:
				err = ALU_or(aa);
				break;
			case OP_XOR:
				err = ALU_xor(aa);
				break;
			case OP_NOT:
				err = ALU_not(aa);
				break;
			case OP_SHL:
				err = ALU_shiftLeft(aa);
				break;
			case OP_SHR:
				err = ALU_shiftRight(aa);
				break;
			default:
				break;
		}

		err = ALU_setStatusWord(aa, rf, sw);
	}
	else
	{
		err = NULL_ERR;
	}

	aa->op_sel = 0x00;

	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_loadA()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int ALU_loadA(ALU, ushort);
 =      Return value ranges: 0 (success), NULL_ERR
 =      Parameter value ranges: pointers to ALU and 16-bit unsigned data value
 =      Error conditions: ALU pointer is null.
 = Simulates the state of the A register as LdA is enabled by explicitly loading an operand into A
 ==================================================================================================*/
int ALU_loadA(ALU aa, ushort input)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL)
	{
		err |= register_putRegValue(aa->A, input);
	}
	else
	{
		err |= NULL_ERR;
	}
	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_loadB()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int ALU_loadB(ALU, ushort);
 =      Return value ranges: 0 (success), NULL_ERR
 =      Parameter value ranges: pointers to ALU and 16-bit unsigned data value
 =      Error conditions: ALU pointer is null.
 = Simulates the state of the B register as LdB is enabled by explicitly loading an operand into B
 ==================================================================================================*/
int ALU_loadB(ALU aa, ushort input)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL)
	{
		err |= register_putRegValue(aa->B, input);
	}
	else
	{
		err |= NULL_ERR;
	}
	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_selectOperation()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int ALU_selectOperation(ALU, uchar)
 =      Return value ranges: 0 (success), NULL_ERR, OP_OUT_OF_RANGE_ERR
 =      Parameter value ranges: pointers to ALU and 8-bit unsigned data value
 =      Error conditions: ALU pointer is null or op is out of range of the defined operations.
 = Simulates the op_sel signal by loading a value into the op_sel register
 ==================================================================================================*/
int ALU_selectOperation(ALU aa, uchar op)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL && op <= OP_SHR)
	{
		aa->op_sel = op;
	}
	else if (aa == NULL)
	{
		err |= NULL_ERR;
	}
	else
	{
		err |= OP_OUT_OF_RANGE_ERR;
	}
	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_setStatusWord()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int ALU_setStatusWord(ALU, RegisterFilePtr, RegisterPtr)
 =      Return value ranges: 0 (success), NULL_ERR
 =      Parameter value ranges: pointers to ALU, register file, and SW register
 =      Error conditions: null pointers.
 = Set the SW status bits to the current status value
 ==================================================================================================*/
int ALU_setStatusWord(ALU aa, RegisterFilePtr rf, RegisterPtr sw)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL && sw != NULL)
	{
		ushort regA = register_getRegValue(aa->A, error);		// fetch values of registers
		ushort regB = register_getRegValue(aa->B, error);
		ushort regC = register_getRegValue(aa->C, error);

		ushort multHigh = registerFile_getRegValue(rf, R9, error);
		ushort multLow = registerFile_getRegValue(rf, R8, error);
		ushort divResult = registerFile_getRegValue(rf, RA, error);
		ushort divRemain = registerFile_getRegValue(rf, RB, error);

		ushort regSW = register_getRegValue(sw, error) & SW_CLEAR_STATUS;

		ushort signA = regA & BIT_15;					// determine sign-bits
		ushort signB = regB & BIT_15;
		ushort signC = regC & BIT_15;
		ushort signMult = multHigh & BIT_15;
		ushort signDivRes = divResult & BIT_15;
		ushort signDivRem = divRemain & BIT_15;


		switch(aa->op_sel)
		{
			case OP_ADD:
				// set N bit
				if(signC == BIT_15)
				{
					regSW = regSW | SW_N_BIT;
				}
				// set Z bit
				if(regC == 0)
				{
					regSW = regSW | SW_Z_BIT;
				}
				// set C bit when (A + B > 0xFFFF)
				if(regA + regB > MAX_USHORT)
				{
					regSW = regSW | SW_C_BIT;
				}
				// set O bit when (+ ADD + = -) or (- ADD - = +)
				if(signA == signB && signA != signC)
				{
					regSW = regSW | SW_O_BIT;
				}
				break;
			case OP_SUB:
				// set N bit
				if(signC == BIT_15)
				{
					regSW = regSW | SW_N_BIT;
				}
				// set Z bit
				if(regC == 0)
				{
					regSW = regSW | SW_Z_BIT;
				}
				// set C bit when (A - B > 0xFFFF)
				if(regA - regB > MAX_USHORT)
				{
					regSW = regSW | SW_C_BIT;
				}
				// set O bit when (+ SUB - = -) or (- SUB + = +)
				if(signA != signB && signA != signC)
				{
					regSW = regSW | SW_O_BIT;
				}
				break;
			case OP_MUL:
				// set N bit
				if(signMult == BIT_15)
				{
					regSW = regSW | SW_N_BIT;
				}
				// set Z bit
				if(multHigh == 0 && multLow == 0)
				{
					regSW = regSW | SW_Z_BIT;
				}
				// set C bit
				// set O bit when (+ MUL + = -) or (- MUL - = -)
				if(signA == signB && signA != signC)
				{
					regSW = regSW | SW_O_BIT;
				}
				break;
			case OP_DIV:
				// set N bit
				if(signDivRes == BIT_15 || signDivRem == BIT_15)
				{
					regSW = regSW | SW_N_BIT;
				}
				// set Z bit
				if(divResult == 0 && divRemain == 0)
				{
					regSW = regSW | SW_Z_BIT;
				}
				// set C bit
				// set O bit
				break;
			case OP_NEG:
				// set N bit
				if(signC == BIT_15)
				{
					regSW = regSW | SW_N_BIT;
				}
				// set Z bit
				if(regC == 0)
				{
					regSW = regSW | SW_Z_BIT;
				}
				// set C bit
				// set O bit
				break;
			case OP_AND:
				// set N bit
				if(signC == BIT_15)
				{
					regSW = regSW | SW_N_BIT;
				}
				// set Z bit
				if(regC == 0)
				{
					regSW = regSW | SW_Z_BIT;
				}
				// set C bit
				// set O bit
				break;
			case OP_OR:
				// set N bit
				if(signC == BIT_15)
				{
					regSW = regSW | SW_N_BIT;
				}
				// set Z bit
				if(regC == 0)
				{
					regSW = regSW | SW_Z_BIT;
				}
				// set C bit
				// set O bit
				break;
			case OP_XOR:
				// set N bit
				if(signC == BIT_15)
				{
					regSW = regSW | SW_N_BIT;
				}
				// set Z bit
				if(regC == 0)
				{
					regSW = regSW | SW_Z_BIT;
				}
				// set C bit
				// set O bit
				break;
			case OP_NOT:
				// set N bit
				if(signC == BIT_15)
				{
					regSW = regSW | SW_N_BIT;
				}
				// set Z bit
				if(regC == 0)
				{
					regSW = regSW | SW_Z_BIT;
				}
				// set C bit
				// set O bit
				break;
			case OP_SHL:
				// set N bit
				if(signC == BIT_15)
				{
					regSW = regSW | SW_N_BIT;
				}
				// set Z bit
				if(regC == 0)
				{
					regSW = regSW | SW_Z_BIT;
				}
				// set C bit
				if(signA == BIT_15)
				{
					regSW = regSW | SW_C_BIT;
				}
				// set O bit
				break;
			case OP_SHR:
				// set N bit
				if(signC == BIT_15)
				{
					regSW = regSW | SW_N_BIT;
				}
				// set Z bit
				if(regC == 0)
				{
					regSW = regSW | SW_Z_BIT;
				}
				// set C bit
				if(regA & 0x0001 == 0x0001)
				{
					regSW = regSW | SW_C_BIT;
				}
				// set O bit
				break;
			default:
				break;
		}

		err |= register_putRegValue(sw, regSW);	// update with new status
	}
	else
	{
		err |= NULL_ERR;
	}
	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_readC()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      ushort	ALU_readC(ALU, int*);
 =      Return value ranges: 16-bit unsigned data value
 =      Parameter value ranges: pointers to ALU and pointer to int for 'read'
				function error codes.
 =      Error conditions: null pointers.
 = Simulates the state of the data bus as DrALU is enabled by explicitly reading the value of C
 ==================================================================================================*/
ushort ALU_readC(ALU aa, int* error)
{
	ushort result = 0;
	if(aa != NULL && error != NULL)
	{
		result = register_getRegValue(aa->C, error);
	}
	else
	{
		*error |= NULL_ERR;
	}
	return result;
}

// INTERNAL FUNCTIONS - functions that simulate the ALU's internal operations

/*=================================================================================================
 = Comment block for function: ALU_add()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int	ALU_add(ALU);
 =      Return value ranges: 0 (success), NULL_ERR
 =      Parameter value ranges: pointers to ALU
 =      Error conditions: null pointer.
 = execute operation A + B
 ==================================================================================================*/
int ALU_add(ALU aa)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL)
	{
		ushort regA = register_getRegValue(aa->A, error);	// fetch values of registers
		ushort regB = register_getRegValue(aa->B, error);

		err |= register_putRegValue(aa->C, regA + regB);
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_sub()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int	ALU_sub(ALU);
 =      Return value ranges: 0 (success), NULL_ERR
 =      Parameter value ranges: pointer to ALU
 =      Error conditions: null pointer.
 = execute operation A - B
 ==================================================================================================*/
int ALU_sub(ALU aa)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL)
	{
		ushort regA = register_getRegValue(aa->A, error);	// fetch values of registers
		ushort regB = register_getRegValue(aa->B, error);

		err |= register_putRegValue(aa->C, regA - regB);
	}
	else
	{
		err |= NULL_ERR;
	}
	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_multiply()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int	ALU_multiply(ALU, RegisterFilePtr);
 =      Return value ranges: 0 (success), NULL_ERR
 =      Parameter value ranges: pointers to ALU and reg_file
 =      Error conditions: null pointers.
 = execute operation A * B
 ==================================================================================================*/
int ALU_multiply(ALU aa, RegisterFilePtr rf)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL && rf != NULL)
	{
		ushort regA = register_getRegValue(aa->A, error);	// fetch values of registers
		ushort regB = register_getRegValue(aa->B, error);

		int tmp = regA * regB;

		err |= registerFile_putRegValue(rf, R8, tmp & LOW_MASK);
		err |= registerFile_putRegValue(rf, R9, tmp & HOW_MASK);
	}
	else
	{
		err |= NULL_ERR;
	}
	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_divide()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int	ALU_divide(ALU, RegisterFilePtr);
 =      Return value ranges: 0 (success), NULL_ERR, ALU_DIVIDE_BY_ZERO
 =      Parameter value ranges: pointers to ALU, reg_file
 =      Error conditions: null pointers, Divide-by-Zero.
 = execute operation A / B
 ==================================================================================================*/
int ALU_divide(ALU aa, RegisterFilePtr rf)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL && rf != NULL)
	{
		ushort regA = register_getRegValue(aa->A, error);	// fetch values of registers
		ushort regB = register_getRegValue(aa->B, error);

		if(regB != 0x00)
		{
			ushort res = regA / regB;
			ushort rem = regA % regB;

			err |= registerFile_putRegValue(rf, RA, res);
			err |= registerFile_putRegValue(rf, RB, rem);
		}
		else
		{
			err |= ALU_DIVIDE_BY_ZERO;
		}
	}
	else
	{
		err |= NULL_ERR;
	}
	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_negate()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int	ALU_negate(ALU);
 =      Return value ranges: 0 (success), NULL_ERR
 =      Parameter value ranges: pointers to ALU
 =      Error conditions: null pointer.
 = execute operation !A + 1
 ==================================================================================================*/
int ALU_negate(ALU aa)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL)
	{
		ushort regA = register_getRegValue(aa->A, error);	// fetch values of register

		err |= register_putRegValue(aa->C, ~regA + 1);
	}
	else
	{
		err |= NULL_ERR;
	}
	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_and()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int	ALU_and(ALU);
 =      Return value ranges: 0 (success), NULL_ERR
 =      Parameter value ranges: pointer to ALU
 =      Error conditions: null pointer.
 = execute operation A & B
 ==================================================================================================*/
int ALU_and(ALU aa)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL)
	{
		ushort regA = register_getRegValue(aa->A, error);	// fetch values of registers
		ushort regB = register_getRegValue(aa->B, error);

		err |= register_putRegValue(aa->C, regA & regB);
	}
	else
	{
		err |= NULL_ERR;
	}
	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_or()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int	ALU_or(ALU);
 =      Return value ranges: 0 (success), NULL_ERR
 =      Parameter value ranges: pointer to ALU
 =      Error conditions: null pointer.
 = execute operation A | B
 ==================================================================================================*/

int ALU_or(ALU aa)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL)
	{
		ushort regA = register_getRegValue(aa->A, error);	// fetch values of registers
		ushort regB = register_getRegValue(aa->B, error);

		err |= register_putRegValue(aa->C, regA | regB);
	}
	else
	{
		err |= NULL_ERR;
	}
	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_xor()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int	ALU_xor(ALU);
 =      Return value ranges: 0 (success), NULL_ERR
 =      Parameter value ranges: pointer to ALU
 =      Error conditions: null pointer.
 = execute operation A XOR B
 ==================================================================================================*/
int ALU_xor(ALU aa)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL)
	{
		ushort regA = register_getRegValue(aa->A, error);	// fetch values of registers
		ushort regB = register_getRegValue(aa->B, error);

		err |= register_putRegValue(aa->C, regA ^ regB);
	}
	else
	{
		err |= NULL_ERR;
	}
	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_not()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int	ALU_not(ALU);
 =      Return value ranges: 0 (success), NULL_ERR
 =      Parameter value ranges: pointer to ALU
 =      Error conditions: null pointer.
 = execute operation !A
 ==================================================================================================*/
int ALU_not(ALU aa)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL)
	{
		ushort regA = register_getRegValue(aa->A, error);	// fetch values of register

		err |= register_putRegValue(aa->C, ~regA);
	}
	else
	{
		err |= NULL_ERR;
	}
	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_shiftLeft()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int	ALU_shiftLeft(ALU);
 =      Return value ranges: 0 (success), NULL_ERR
 =      Parameter value ranges: pointer to ALU
 =      Error conditions: null pointer.
 = execute operation bit shift left
 ==================================================================================================*/
int ALU_shiftLeft(ALU aa)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL)
	{
		ushort regA = register_getRegValue(aa->A, error);	// fetch values of register

		*aa->C = *aa->A << 1;
		err |= register_putRegValue(aa->C, regA << 1);
	}
	else
	{
		err |= NULL_ERR;
	}
	return err;
}

/*=================================================================================================
 = Comment block for function: ALU_shiftRight()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      int	ALU_shiftRight(ALU);
 =      Return value ranges: 0 (success), NULL_ERR
 =      Parameter value ranges: pointers to ALU
 =      Error conditions: null pointers.
 = execute operation A >> C
 ==================================================================================================*/

int ALU_shiftRight(ALU aa)
{
	int err = 0;
	int* error = &err;

	if(aa != NULL)
	{
		ushort regA = register_getRegValue(aa->A, error);	// fetch values of register

		err |= register_putRegValue(aa->C, regA >> 1);
	}
	else
	{
		err |= NULL_ERR;
	}
	return err;
}




/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 +  Memory Module ADT implementation
 +
 +  Basic Operations
 +		Initialize: 	allocates space for memory of uchar(s), fills memory with random values
 +				between 0 and 0xFF
 +		FetchByteFrom: 	returns a single uchar from location indicated
 +		StoreByteTo: 	puts a uchar into the memory location indicated
 +		Destructor: 	not needed
 +
 +  Composite Operations
 +		FetchWordFrom: 	returns a ushort (word) from the memory location indicated
 +		StoreWordTo: 	puts a ushort into consecutive memory locations starting with
 +				address given
 +
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*=====================================================================================================
 =   	Comment block for function: memory_initialize()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		MemoryModulePtr memory_initialize()
 =	return value ranges: 	pointer value
 =	parameter value ranges: no parameters
 =	error conditions:	no error conditions
 =
 =	creates user memory space and returns a pointer
 =
 ====================================================================================================*/

MemoryModulePtr memory_initialize() 	// creates user memory space and fills with random numbers
{
	MemoryModulePtr mm = (MemoryModulePtr) malloc(sizeof(uchar) * (MEM_SIZE));

	int i;
	for (i = MEM_FIRST; i <= MEM_LAST; i++)
	{
		memory_storeByteTo(mm, i, rand() * 0xFF);
	}

	return mm;
}

/*=====================================================================================================
 =   	Comment block for function: memory_fetchByteFrom()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		uchar memory_fetchByteFrom(MemoryModulePtr, ushort, int *)
 =	return value ranges: 	uchar (8-bits)
 =	parameter value ranges: MemoryModulePtr, memory address, pointer to error flag (int)
 =	error conditions:  	Memory Address out of range - ERROR_MEM_OUT_OF_RANGE
 =				MemoryModulePtr undefined - NULL_ERR
 =
 =	returns a byte form address, sets error code
 =
 ====================================================================================================*/
uchar memory_fetchByteFrom(MemoryModulePtr mm, ushort address, int* error)
{						// returns a byte form address, sets error code
	uchar byte = 0x0;

	if(mm != NULL)
	{
		int index = address - MEM_FIRST;

		if ((index >= 0x0) && (index <= MEM_SIZE))			// if valid address
		{
			byte = mm[index];					// get contents of memory
		}
		else
		{
			*error |= ERROR_MEM_OUT_OF_RANGE;			// else set error code
		}
	}
	else
	{
		*error |= NULL_ERR;
	}

	return byte;
}

/*=====================================================================================================
 =   	Comment block for function: memory_storeByteTo()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int memory_storeByteTo(MemoryModulePtr, ushort, uchar)
 =	return value ranges: 	error code
 =	parameter value ranges: MemoryModulePtr, memory address, 8-bit uchar data
 =	error conditions:  	Memory Address out of range - ERROR_MEM_OUT_OF_RANGE
 =
 =	puts a byte into memory, returns error code
 =
 ====================================================================================================*/
int memory_storeByteTo(MemoryModulePtr mm, ushort address, uchar byte) 	// stores byte at address,
{									// returns error code
	int error_code = 0x0;
	int index = address - MEM_FIRST;

	if(mm != NULL)
	{
		if ((index >= 0x0) && (index <= MEM_SIZE))			// if valid address
		{
			mm[index] = byte;					// put byte into memory
		}
		else
		{
			error_code |= ERROR_MEM_OUT_OF_RANGE;			// else set error code
		}
	}
	else
	{
		error_code |= NULL_ERR;
	}
	return error_code;
}


/*=====================================================================================================
 =   	Comment block for function: memory_fetchWordFrom()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		ushort memory_fetchWordFrom(MemoryModulePtr, ushort, int *)
 =	return value ranges: 	ushort
 =	parameter value ranges: MemoryModulePtr, memory address, pointer to error flag (int)
 =	error conditions:  	Memory Address out of range - ERROR_MEM_OUT_OF_RANGE
 =
 =	returns the contents of 2 memory locations starting at the given address. sets error code
 =
 ====================================================================================================*/
ushort memory_fetchWordFrom(MemoryModulePtr mm, ushort address, int* error)
{						// returns the contents	of two consecutive
						// locations starting at address. sets error code

	ushort word = 0x0;
	uchar lobyte;
	uchar hibyte;

	int index = address - MEM_FIRST;

	if(mm != NULL)
	{
		if ((index >= 0x0) && (index < MEM_SIZE))			// if valid address
		{
			hibyte = memory_fetchByteFrom(mm, address, error);
			lobyte = memory_fetchByteFrom(mm, address + 1, error);

			word = hibyte * 0x100;					// store HOB
			word = word + lobyte;					// store LOB
		}
		else
		{
			*error |= ERROR_MEM_OUT_OF_RANGE;		// else set error code
		}
	}
	else
	{
		*error |= NULL_ERR;
	}
	return word;
}


/*=====================================================================================================
 =   	Comment block for function: memory_storeWordTo()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int memory_storeWordTo(MemoryModulePtr, ushort, ushort)
 =	return value ranges: 	error code
 =	parameter value ranges: MemoryModulePtr, memory address, 16-bit ushort data
 =	error conditions:  	Memory Address out of range - ERROR_MEM_OUT_OF_RANGE
 =
 =	writes the ushort data to the 2 memory locations starting at the given address.
 =	returns error code.
 =
 ====================================================================================================*/
int memory_storeWordTo(MemoryModulePtr mm, ushort address, ushort word)
{
	int error_code = 0x0;
	int index = address - MEM_FIRST;
	if(mm != NULL)
	{
		if ((index >= 0x0) && (index <= MEM_SIZE - 1))			// if valid address
		{
			uchar hibyte = (word & HOB_MASK) >> 8;
			uchar lobyte = word & LOB_MASK;

			error_code |= memory_storeByteTo(mm, address, hibyte);		// put HOB into memory
			error_code |= memory_storeByteTo(mm, address + 1, lobyte);	// put LOB into memory
		}
		else
		{
			error_code |= ERROR_MEM_OUT_OF_RANGE;			// else set error code
		}
	}
	else
	{
		error_code |= NULL_ERR;
	}
	return error_code;
}

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 +  Input Output ADT implementation
 +
 +  Basic Operations:
 +		Initialize: allocates space for ports of uchar(s), fills ports with random values
 +				between 0 and 0xFF
 +		Input: Retrieves a uchar from selected port.
 +		Output: Stores uchar to selected port.
 +
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/*=====================================================================================================
 =   	Comment block for function: io_input()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		uchar io_input(ushort, int *)
 =	return value ranges: 	uchar (8-bits)
 =	parameter value ranges: port address, pointer to error flag (int)
 =	error conditions:  	Port is not KBD -> INVALID_PORT_ERR
 =
 =	returns a byte from input port, sets error code
 =
 ====================================================================================================*/
uchar io_input(ushort the_port, int * the_error)
{						// returns a byte from input port, sets error code
	uchar byte = 0x0;
    if (the_port == KBD)			// if valid address
    {
        byte = getc(stdin);					// get contents of memory
    }
    else
    {
        * the_error |= INVALID_PORT_ERR;			// else set error code
    }

	return byte;
}

/*=====================================================================================================
 =   	Comment block for function: io_output()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int io_output(ushort, uchar)
 =	return value ranges: 	error code
 =	parameter value ranges: port address, 8-bit uchar data
 =	error conditions:  	Port is not VID -> INVALID_PORT_ERR
 =
 =	puts a byte into selected port, returns error code
 =
 ====================================================================================================*/
int io_output(ushort the_port, uchar the_byte)
{
    int error_code = 0x0;
    if (the_port == VID)			// if valid address
    {
        putc(the_byte, stdout);					// put byte into stdout
    }
    else
    {
        error_code |= INVALID_PORT_ERR;			// else set error code
    }
	return error_code;
}

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 +  Controller ADT implementation
 +
 +  External Operations:
 +	Initialize:  creates controller object with initial state set to FETCH and returns a pointer.
 +
 +	Step:	evaluates current state, calls the appropriate function, then advances the controller
 + 		to the next state. Checks the CPU's Halt bit before returning to the FETCH state.
 +
 +	Internal Operations:
 +	Fetch:	(needs CPU* and Memory*) retrieves word stored at
 +		location pointed to by the PC, stores it in the CPU's IR
 +		register, and increments the PC (calls CPU function to inc PC?)
 +
 +	Decode:  (needs IR*) Splits out the opcode portion of the command in
 +		the IR.
 +
 +	Execute:  evaluates the opcode in a switch to execute the command.
 +
 +	Parse Operands: called from Execute, parses and temporarily stores operands.
 +
 +	Load/Store Operations:
 +	Execute LDI:  parse operands and execute.
 +	Execute LADR:  parse operand and execute.
 +	Execute LDB:  parse operands and execute.
 +	Execute LDW:  parse operands and execute.
 -	Execute STB:  parse operands and execute.
 -	Execute STW:  parse operands and execute.
 -	Execute MOVB:  parse operands and execute.
 -	Execute MOVW:  parse operands and execute.
 -
 -	ALU Operations:
 -	Execute ADDI:  parse operands and execute.
 -	Execute ADD:  parse operands and execute.
 -	Execute SUBI:  parse operands and execute.
 -	Execute SUB:  parse operands and execute.
 -	Execute NEG:  parse operand and execute.
 -	Execute AND:  parse operands and execute.
 -	Execute OR:  parse operands and execute.
 -	Execute NOT:  parse operand and execute.
 -	Execute SHL:  parse operand and execute.
 -	Execute SHR:  parse operand and execute.
 +
 +	Flow of Control Operations:
 +	Execute BR:  parse operand and execute.
 +	Execute BRcc:  parse operand and execute.
 +
 +	I/O Operations:
 +	Execute IN:  parse operand and execute.
 +	Execute OUT:  parse operand and execute.
 +
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*=====================================================================================================
 =   	Comment block for function: controller_initialize()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		Controller controller_initialize()
 =	return value ranges: 	pointer to controller
 =	parameter value ranges: N/A
 =	error conditions:  	N/A
 =
 =	creates controller object with initial state set to FETCH and returns a pointer.
 =
 ====================================================================================================*/
Controller controller_initialize()
{
	Controller cc = (Controller) malloc(sizeof(ControllerStr));
	cc->curr_state = FETCH;

	return cc;
}

/*=====================================================================================================
 =   	Comment block for function: controller_step()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:	int controller_step(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal, Memory mem)
 =	return value ranges: 	0 (success), NULL_ERR, ERROR_MEM_OUT_OF_RANGE, PROGRAM_HALT
 =	parameter value ranges: pointers to controller, register file, internal registers, and memory module
 =	error conditions:  	null pointers, adjusted PC value outside of allocated memory module,
 =				halt bit set.
 =
 =	calls controller functions based on current state, then advances the state.
 =
 ====================================================================================================*/
int controller_step(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal, Memory mem)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && the_internal != NULL && mem != NULL)
	{
		switch (cc->curr_state)
		{
			case FETCH:
				err |= controller_fetch(the_internal, mem);	// load IR from mem
				cc->curr_state = DECODE;
				break;
			case DECODE:
				err |= controller_decode(cc, the_internal);	// parse opcode from IR
				cc->curr_state = EXECUTE;
				break;
			case EXECUTE:
				err |= controller_execute(cc, reg_file, the_alu, the_internal, mem);// execute opcode
				if(internalRegisters_checkHalt(the_internal, error) == FALSE)
					cc->curr_state = FETCH;
				else
					err |= PROGRAM_HALT;		// flag end of program
				break;
			default:
				break;
		}
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_fetch()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_fetch(InternalRegisters the_internal, Memory mem)
 =	return value ranges: 	0 (success), NULL_ERR, ERROR_MEM_OUT_OF_RANGE
 =	parameter value ranges: the_internal and mem are valid pointers.
 =	error conditions:  	null pointers, adjusted PC value outside of allocated memory module
 =
 =	tests PC to see if it is within range and fetches the instruction stored at that address,
 =	then increments PC to point to next instruction.
 =
 ====================================================================================================*/
int controller_fetch(InternalRegisters the_internal, Memory mem)
{
	int err = 0;
	if(the_internal != NULL && mem != NULL)
	{
		ushort pc = internalRegisters_getPC(the_internal, &err);

		if(pc >= MEM_FIRST && pc < MEM_LAST && pc % 2 == 0)	// pc in mem range & on a word boundary
		{
			err |= internalRegisters_setIR(the_internal, memory_fetchWordFrom(mem, pc, &err));
			err |= internalRegisters_setPC(the_internal, pc + 2);	// increment the PC by two.
		}
		else
		{
			err |= ERROR_MEM_OUT_OF_RANGE;
		}
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_decode()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_decode(Controller cc, InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR, OP_OUT_OF_RANGE_ERR
 =	parameter value ranges: cc and the_internal are valid pointers.
 =	error conditions:  	null pointers, invalid opcode
 =
 =	parses opcode portion of instruction and tests to see if valid for this simulation.
 =
 ====================================================================================================*/
int controller_decode(Controller cc, InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && the_internal != NULL)
	{
		cc->op_code = internalRegisters_getIR(the_internal, error) / OPCODE_SHIFT; // fetch opcode

		switch(cc->op_code)	// commented out duplicate op_codes
		{
			case OPCODE_LDI:
			case OPCODE_LADR:
			case OPCODE_LDB:
			case OPCODE_LDW:
			case OPCODE_STB:
			case OPCODE_STW:
			//case OPCODE_MOVB:
			//case OPCODE_MOVW:
			case OPCODE_ADDI:
			case OPCODE_ADD:
			case OPCODE_SUBI:
			case OPCODE_SUB:
			case OPCODE_NEG:
			case OPCODE_AND:
			case OPCODE_OR:
			case OPCODE_NOT:
			case OPCODE_SHL:
			//case OPCODE_SHR:
			case OPCODE_BR:
			case OPCODE_BRCC:
			//case OPCODE_IN:
			case OPCODE_OUT:
				break;
			default:
				err |= OP_OUT_OF_RANGE_ERR;
				break;
		}
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_execute()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:	int controller_execute(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal, Memory mem)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, internal registers, and memory
 =	error conditions:  	null pointers,
 =
 =	parses operands and executes operation.
 =
 ====================================================================================================*/
int controller_execute(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal, Memory mem)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && the_internal != NULL && mem != NULL)
	{
		err |= controller_parseOperands(cc, the_internal);

		switch(cc->op_code)
		{
			case OPCODE_LDI:
				err |= controller_exec_LDI(cc, reg_file);
				break;
			case OPCODE_LADR:
				err |= controller_exec_LADR(cc, reg_file, the_internal, mem);
				break;
			case OPCODE_LDB:			// same opcode as MOVB
				if(cc->operand_3 == AMOD_4)	// AMOD
				{
					err |= controller_exec_MOVB(cc, reg_file);
				}
				else
				{
					err |= controller_exec_LDB(cc, reg_file, mem);
				}
				break;
			case OPCODE_LDW:			// same opcode as MOVW
				if(cc->operand_3 == AMOD_5)	// AMOD
				{
					err |= controller_exec_MOVW(cc, reg_file);
				}
				else
				{
					err |= controller_exec_LDW(cc, reg_file, mem);
				}
				break;
			case OPCODE_STB:
				err |= controller_exec_LDB(cc, reg_file, mem);
				break;
			case OPCODE_STW:
				err |= controller_exec_STW(cc, reg_file, mem);
				break;
			case OPCODE_ADDI:
				err |= controller_exec_ADDI(cc, reg_file, the_alu, the_internal);
				break;
			case OPCODE_ADD:
				err |= controller_exec_ADD(cc, reg_file, the_alu, the_internal);
				break;
			case OPCODE_SUBI:
				err |= controller_exec_SUBI(cc, reg_file, the_alu, the_internal);
				break;
			case OPCODE_SUB:
				err |= controller_exec_SUB(cc, reg_file, the_alu, the_internal);
				break;
			case OPCODE_NEG:
				err |= controller_exec_NEG(cc, reg_file, the_alu, the_internal);
				break;
			case OPCODE_AND:
				err |= controller_exec_AND(cc, reg_file, the_alu, the_internal);
				break;
			case OPCODE_OR:
				err |= controller_exec_OR(cc, reg_file, the_alu, the_internal);
				break;
			case OPCODE_NOT:
				err |= controller_exec_NOT(cc, reg_file, the_alu, the_internal);
				break;
			case OPCODE_SHL:
				if(cc->operand_3 == AMOD_1)
				{
					err |= controller_exec_SHR(cc, reg_file, the_alu, the_internal);
				}
				else
				{
					err |= controller_exec_SHL(cc, reg_file, the_alu, the_internal);
				}
				break;
			case OPCODE_BR:
				err |= controller_exec_BR(cc, reg_file, the_internal);
				break;
			case OPCODE_BRCC:
				err |= controller_exec_BRcc(cc, reg_file, the_internal);
				break;
			case OPCODE_IN:
				err |= controller_exec_IN(cc, reg_file);
				break;
			case OPCODE_OUT:
				err |= controller_exec_OUT(cc, reg_file);
				break;
			case OPCODE_HALT:
				err |= controller_exec_HALT(the_internal);
				break;
			default:
				break;
		}
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_parseOperands()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_parseOperands(Controller cc, InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR, INVALID_OPERAND_ERR
 =	parameter value ranges: cc and the_internal are valid pointers, value for instruction format (0-6)
 =	error conditions:  	null pointers
 =
 =	parses operands based on instruction format.
 =
 ====================================================================================================*/
int controller_parseOperands(Controller cc, InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && the_internal != NULL)
	{
		ushort ir = internalRegisters_getIR(the_internal, error); 	// fetch value in IR

		switch(cc->op_code)	// * == duplicate op_codes
		{
			// format 0
			case OPCODE_LDI:	//0x01
			case OPCODE_ADDI:	//0x08
			case OPCODE_SUBI:	//0x09
				cc->operand_1 = (ir & OPERAND1_FILTER) / OPERAND1_SHIFT;
				cc->operand_2 = ir & IMMED7_FILTER;	// immediate value
				break;
			// format 6
			case OPCODE_IN:		// 0x18
			case OPCODE_OUT:	// 0x19
				cc->operand_1 = ir & IMMED11_FILTER;
				break;
			default:
			// format 1-5 and 7 use the same basic pattern.
			// case OPCODE_LDB:	//0x02
			// case OPCODE_LDW:	//0x03
			// case OPCODE_STB:	//0x06
			// case OPCODE_STW:	//0x07
			// * case OPCODE_MOVB:	//0x02	AMOD = 0x04
			// * case OPCODE_MOVW:	//0x03	AMOD = 0x05
			// case OPCODE_SHL:	//0x1E
			// * case OPCODE_SHR:	//0x1E	AMOD = 0x01
			// case OPCODE_BR:	//0x13
			//  * case OPCODE_BRCC:	//0x14?	AMOD: N = 0x01, Z = 0x02, C = 0x03, O = 0x04
			// case OPCODE_ADD:	// 0x0A
			// case OPCODE_SUB:	// 0x0B
			// case OPCODE_AND:	// 0x0E
			// case OPCODE_OR:	// 0x0F
			// case OPCODE_LADR:	// 0x17
			// case OPCODE_NEG:	// 0x11
			// case OPCODE_NOT:	// 0x12
				cc->operand_1 = (ir & OPERAND1_FILTER) / OPERAND1_SHIFT;
				cc->operand_2 = (ir & OPERAND2_FILTER) / OPERAND2_SHIFT;
				cc->operand_3 = ir & OPERAND3_FILTER;
				break;
		}
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_LDI()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_LDI(Controller, RegisterFilePtr)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller and register file
 =	error conditions:  	null pointer
 =
 =	Load Immediate - $Rd <- immed7; pad with leading 0's (0's will automatically be prepended)
 =
 ====================================================================================================*/
int controller_exec_LDI(Controller cc, RegisterFilePtr reg_file)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL)
	{
		err |= registerFile_putRegValue(reg_file, cc->operand_1, cc->operand_2);
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_LADR()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:	int controller_exec_LADR(Controller cc, RegisterFilePtr reg_file, InternalRegisters the_internal, Memory mem)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, internal registers, and memory module
 =	error conditions:  	null pointers
 =
 =	Load Address - $Rd <- M[PC] << 8; $Rd <- M[PC+1]; PC <- PC+2 (memory_fetchWordFrom()
 = 				handles shifting and combining the bytes for us)
 =
 ====================================================================================================*/
int controller_exec_LADR(Controller cc, RegisterFilePtr reg_file, InternalRegisters the_internal, Memory mem)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && the_internal != NULL && mem != NULL)
	{
		// get PC value and store word starting at that loc in register
		ushort pc = internalRegisters_getPC(the_internal, error);
		ushort address = memory_fetchWordFrom(mem, pc, error);		// fetch address from mem

		err |= registerFile_putRegValue(reg_file, cc->operand_1, address);

		err |= internalRegisters_setPC(the_internal, pc + 2);	// increment the PC by two.
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_LDB()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_LDB(Controller cc, RegisterFilePtr reg_file, Memory mem)
 =	return value ranges: 	0 (success), NULL_ERR, INCORRECT_OPERAND_ERR
 =	parameter value ranges: pointers to controller, register file, and memory module
 =	error conditions:  	null pointers, $Rd (operand 1) not $R0-$R3
 =
 =	Load Byte - $Rdlow (op1) <- M[$Rr (op2)] ; only for $R0-$R3 $Rr can be any reg
 =
 ====================================================================================================*/
int controller_exec_LDB(Controller cc, RegisterFilePtr reg_file, Memory mem)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && mem != NULL)
	{
		if(cc->operand_1 >= R0 && cc->operand_1 <= R3)	// test for legal register value
		{
			// I'm thinking this doesn't touch $Rdhigh at all, does it... -TB
			ushort address = registerFile_getRegValue(reg_file, cc->operand_2, error); // fetch address
			uchar value = memory_fetchByteFrom(mem, address, error);	// fetch value from address

			err |= registerFile_putByteTo(reg_file, cc->operand_1, LOB_WHICH, value); // store in $Rd
		}
		else
		{
			err |= INCORRECT_OPERAND_ERR;
		}
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_LDW()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_LDW(Controller cc, RegisterFilePtr reg_file, Memory mem)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, and memory module
 =	error conditions:  	null pointers
 =
 =	LDW $Rd, $Rr		;$Rdlow <- M[$Rr], $Rdhigh <- M[$Rr + 1]; any register
 =
 ====================================================================================================*/
int controller_exec_LDW(Controller cc, RegisterFilePtr reg_file, Memory mem)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && mem != NULL)
	{
		ushort address = registerFile_getRegValue(reg_file, cc->operand_2, error); // fetch address from $Rr
		ushort value = memory_fetchWordFrom(mem, address, error);		// fetch value from address

		err |= registerFile_putRegValue(reg_file, cc->operand_1, value); 	// store in $Rd
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_STB()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_STB(Controller cc, RegisterFilePtr reg_file, Memory mem)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, and memory module
 =	error conditions:  	null pointers
 =
 =	STB $Rs, $Rr 		;M[$Rr] <- $Rslow
 =
 ====================================================================================================*/
int controller_exec_STB(Controller cc, RegisterFilePtr reg_file, Memory mem)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && mem != NULL)
	{
		ushort address = registerFile_getRegValue(reg_file, cc->operand_2, error); 	// get address
		uchar value = registerFile_getByteFrom(reg_file, cc->operand_1, LOB_WHICH, error); // get value

		err |= memory_storeByteTo(mem, address, value);	// store at address
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_STW()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:	int controller_exec_STW(Controller cc, RegisterFilePtr reg_file, Memory mem)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, and memory module
 =	error conditions:  	null pointers
 =
 =	STW $Rs, $Rr		;M[$Rr] <- $Rslow; M[$Rr + 1] <- $Rshigh
 =
 ====================================================================================================*/
int controller_exec_STW(Controller cc, RegisterFilePtr reg_file, Memory mem)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && mem != NULL)
	{
		ushort address = registerFile_getRegValue(reg_file, cc->operand_2, error); // get address
		ushort value = registerFile_getRegValue(reg_file, cc->operand_1, error);	// get value

		err |= memory_storeWordTo(mem, address, value);		// store to memory
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_MOVB()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_MOVB(Controller cc, RegisterFilePtr reg_file)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller and register file
 =	error conditions:  	null pointers
 =
 =	MOVB $Rd, $Rs		;$Rdlow <- $Rslow ; only for $R0- $R3
 =
 ====================================================================================================*/
int controller_exec_MOVB(Controller cc, RegisterFilePtr reg_file)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL)
	{
		if(cc->operand_1 >= R0 && cc->operand_1 <= R3)	// test for legal register value
		{
			uchar value = registerFile_getByteFrom(reg_file, cc->operand_2, LOB_WHICH, error); // fetch value

			err |= registerFile_putByteTo(reg_file, cc->operand_1, LOB_WHICH, value); // store in $Rd
		}
		else
		{
			err |= INCORRECT_OPERAND_ERR;
		}
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_MOVW()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_MOVW(Controller cc, RegisterFilePtr reg_file)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, and register file
 =	error conditions:  	null pointers
 =
 =	MOVW $Rd, $Rs		;$Rd <- $Rs
 =
 ====================================================================================================*/
int controller_exec_MOVW(Controller cc, RegisterFilePtr reg_file)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL)
	{
		ushort value = registerFile_getRegValue(reg_file, cc->operand_2, error); // get value

		err |= registerFile_putRegValue(reg_file, cc->operand_1, value); 	// store in $Rd
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_ADDI()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:	int controller_exec_ADDI(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, alu, and internal registers
 =	error conditions:  	null pointers
 =
 =	ADDI $Rd, immed7	;$Rd <- $Rd + SEXT(immed7)
 =
 ====================================================================================================*/
int controller_exec_ADDI(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && the_alu != NULL && the_internal != NULL)
	{
		ushort value = registerFile_getRegValue(reg_file, cc->operand_1, error); // get value
		err |= ALU_loadA(the_alu, value);				// load A with value
		err |= ALU_loadB(the_alu, cc->operand_2);			// load B with immed7 value
		err |= ALU_selectOperation(the_alu, OP_ADD);			// select addition

		ALU_execute(the_alu, reg_file, the_internal->sw);			// execute operation

		value = ALU_readC(the_alu, error);				// read c
		err |= registerFile_putRegValue(reg_file, cc->operand_1, value); 	// store in $Rd
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_ADD()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_ADD(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, alu, and internal registers
 =	error conditions:  	null pointers
 =
 =	ADD $Rd, $Rs		;$Rd <- $Rd + $Rs
 =
 ====================================================================================================*/
int controller_exec_ADD(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && the_alu != NULL && the_internal != NULL)
	{
		ushort valueA = registerFile_getRegValue(reg_file, cc->operand_1, error); // get valueA
		ushort valueB = registerFile_getRegValue(reg_file, cc->operand_2, error); // get valueB

		err |= ALU_loadA(the_alu, valueA);				// load A with value
		err |= ALU_loadB(the_alu, valueB);				// load B with value
		err |= ALU_selectOperation(the_alu, OP_ADD);			// select addition

		ALU_execute(the_alu, reg_file, the_internal->sw);			// execute operation

		valueA = ALU_readC(the_alu, error);				// read c
		err |= registerFile_putRegValue(reg_file, cc->operand_1, valueA); 	// store in $Rd
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_SUBI()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_SUBI(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, alu, and internal registers
 =	error conditions:  	null pointers
 =
 =	SUBI $Rd, immed7	;$Rd <- $Rd - SEXT(immed7)
 =
 ====================================================================================================*/
int controller_exec_SUBI(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && the_alu != NULL && the_internal != NULL)
	{
		ushort value = registerFile_getRegValue(reg_file, cc->operand_1, error); // get value
		err |= ALU_loadA(the_alu, value);				// load A with value
		err |= ALU_loadB(the_alu, cc->operand_2);			// load B with immed7 value
		err |= ALU_selectOperation(the_alu, OP_SUB);			// select subtraction

		ALU_execute(the_alu, reg_file, the_internal->sw);			// execute operation

		value = ALU_readC(the_alu, error);				// read c
		err |= registerFile_putRegValue(reg_file, cc->operand_1, value); 	// store in $Rd
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_SUB()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_SUB(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, alu, and internal registers
 =	error conditions:  	null pointers
 =
 =	SUB $Rd, $Rs		;$Rd <- $Rd - $Rs
 =
 ====================================================================================================*/
int controller_exec_SUB(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && the_alu != NULL && the_internal != NULL)
	{
		ushort valueA = registerFile_getRegValue(reg_file, cc->operand_1, error); // get valueA
		ushort valueB = registerFile_getRegValue(reg_file, cc->operand_2, error); // get valueB

		err |= ALU_loadA(the_alu, valueA);				// load A with value
		err |= ALU_loadB(the_alu, valueB);				// load B with value
		err |= ALU_selectOperation(the_alu, OP_SUB);			// select subtraction

		ALU_execute(the_alu, reg_file, the_internal->sw);			// execute operation

		valueA = ALU_readC(the_alu, error);				// read c
		err |= registerFile_putRegValue(reg_file, cc->operand_1, valueA); 	// store in $Rd
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_NEG()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_NEG(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, alu, and internal registers
 =	error conditions:  	null pointers
 =
 =	NEG $Rd			;$Rd <- ~$Rd + 1
 =
 ====================================================================================================*/
int controller_exec_NEG(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && the_alu != NULL && the_internal != NULL)
	{
		ushort valueA = registerFile_getRegValue(reg_file, cc->operand_1, error); // get valueA

		err |= ALU_loadA(the_alu, valueA);				// load A with value
		err |= ALU_selectOperation(the_alu, OP_NEG);			// select negation

		ALU_execute(the_alu, reg_file, the_internal->sw);			// execute operation

		valueA = ALU_readC(the_alu, error);				// read c
		err |= registerFile_putRegValue(reg_file, cc->operand_1, valueA); 	// store in $Rd
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_AND()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_AND(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, alu, and internal registers
 =	error conditions:  	null pointers
 =
 =	AND $Rd, $Rs		;$Rd <- $Rd & $Rs

 =
 ====================================================================================================*/
int controller_exec_AND(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && the_alu != NULL && the_internal != NULL)
	{
		ushort valueA = registerFile_getRegValue(reg_file, cc->operand_1, error); // get valueA
		ushort valueB = registerFile_getRegValue(reg_file, cc->operand_2, error); // get valueB

		err |= ALU_loadA(the_alu, valueA);				// load A with value
		err |= ALU_loadB(the_alu, valueB);				// load B with value
		err |= ALU_selectOperation(the_alu, OP_AND);			// select AND

		ALU_execute(the_alu, reg_file, the_internal->sw);			// execute operation

		valueA = ALU_readC(the_alu, error);				// read c
		err |= registerFile_putRegValue(reg_file, cc->operand_1, valueA); 	// store in $Rd
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_OR()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_OR(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, alu, and internal registers
 =	error conditions:  	null pointers
 =
 =	AND $Rd, $Rs		;$Rd <- $Rd | $Rs

 =
 ====================================================================================================*/
int controller_exec_OR(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && the_alu != NULL && the_internal != NULL)
	{
		ushort valueA = registerFile_getRegValue(reg_file, cc->operand_1, error); // get valueA
		ushort valueB = registerFile_getRegValue(reg_file, cc->operand_2, error); // get valueB

		err |= ALU_loadA(the_alu, valueA);				// load A with value
		err |= ALU_loadB(the_alu, valueB);				// load B with value
		err |= ALU_selectOperation(the_alu, OP_OR);			// select OR

		ALU_execute(the_alu, reg_file, the_internal->sw);			// execute operation

		valueA = ALU_readC(the_alu, error);				// read c
		err |= registerFile_putRegValue(reg_file, cc->operand_1, valueA); 	// store in $Rd
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_NOT()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_NOT(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, alu, and internal registers
 =	error conditions:  	null pointers
 =
 =	NEG $Rd			;$Rd <- ~$Rd
 =
 ====================================================================================================*/
int controller_exec_NOT(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && the_alu != NULL && the_internal != NULL)
	{
		ushort valueA = registerFile_getRegValue(reg_file, cc->operand_1, error); // get valueA

		err |= ALU_loadA(the_alu, valueA);				// load A with value
		err |= ALU_selectOperation(the_alu, OP_NOT);			// select inversion

		ALU_execute(the_alu, reg_file, the_internal->sw);			// execute operation

		valueA = ALU_readC(the_alu, error);				// read c
		err |= registerFile_putRegValue(reg_file, cc->operand_1, valueA); 	// store in $Rd
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_SHL()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_SHL(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, alu, and internal registers
 =	error conditions:  	null pointers
 =
 =	SHL $Rd, $Rs		;$Rd <- $Rs * 2
 =
 ====================================================================================================*/
int controller_exec_SHL(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && the_alu != NULL && the_internal != NULL)
	{
		ushort valueA = registerFile_getRegValue(reg_file, cc->operand_2, error); // get valueA

		err |= ALU_loadA(the_alu, valueA);				// load A with value
		err |= ALU_selectOperation(the_alu, OP_SHL);			// select Shift-Left

		ALU_execute(the_alu, reg_file, the_internal->sw);			// execute operation

		valueA = ALU_readC(the_alu, error);				// read c
		err |= registerFile_putRegValue(reg_file, cc->operand_1, valueA); 	// store in $Rd
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_SHR()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_SHR(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, alu, and internal registers
 =	error conditions:  	null pointers
 =
 =	SHR $Rd, $Rs		;$Rd <- $Rs / 2
 =
 ====================================================================================================*/
int controller_exec_SHR(Controller cc, RegisterFilePtr reg_file, ALU the_alu, InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && the_alu != NULL && the_internal != NULL)
	{
		ushort valueA = registerFile_getRegValue(reg_file, cc->operand_2, error); // get valueA

		err |= ALU_loadA(the_alu, valueA);				// load A with value
		err |= ALU_selectOperation(the_alu, OP_SHR);			// select Shift-Right

		ALU_execute(the_alu, reg_file, the_internal->sw);			// execute operation

		valueA = ALU_readC(the_alu, error);				// read c
		err |= registerFile_putRegValue(reg_file, cc->operand_1, valueA); 	// store in $Rd
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_BR()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:	int controller_exec_BR(Controller cc, RegisterFilePtr reg_file, InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, and internal registers
 =	error conditions:  	null pointers
 =
 =	BR $Rr			;PC <- $Rr; branch absolute
 =
 ====================================================================================================*/
int controller_exec_BR(Controller cc, RegisterFilePtr reg_file, InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && the_internal != NULL)
	{
		ushort address = registerFile_getRegValue(reg_file, cc->operand_1, error); // fetch address
		err |= internalRegisters_setPC(the_internal, address); // load address into PC
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_BRcc()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_BRcc(Controller cc, RegisterFilePtr reg_file, InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller, register file, and internal registers
 =	error conditions:  	null pointers
 =
 =	BRcc $Rr		;if (cc) PC <- $Rr; else PC unaffected; cc = N, Z, C, O
 =				;AMOD: N = 0x01, Z = 0x02, C = 0x03, O = 0x04
 =
 ====================================================================================================*/
int controller_exec_BRcc(Controller cc, RegisterFilePtr reg_file, InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL && the_internal != NULL)
	{
		ushort address = registerFile_getRegValue(reg_file, cc->operand_1, error); // fetch address
		ushort sw = internalRegisters_getSW(the_internal, error);	// fetch status word

		if(	(cc->operand_3 == AMOD_N && (sw & SW_N_BIT) == SW_N_BIT) ||
			(cc->operand_3 == AMOD_Z && (sw & SW_Z_BIT) == SW_Z_BIT) ||
			(cc->operand_3 == AMOD_O && (sw & SW_O_BIT) == SW_O_BIT) ||
			(cc->operand_3 == AMOD_C && (sw & SW_C_BIT) == SW_C_BIT) 	)
		{
			err |= internalRegisters_setPC(the_internal, address); // load address into PC
		}
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_IN()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_IN(Controller cc, RegisterFilePtr reg_file)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller and register file
 =	error conditions:  	null pointers
 =
 =	IN port#		;$R0low <- IO[port#]; if port is write only results are undefined
 =
 ====================================================================================================*/
int controller_exec_IN(Controller cc, RegisterFilePtr reg_file)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL)
	{
		uchar value = io_input(KBD, error);			// get a byte from the keyboard
		err |= registerFile_putByteTo(reg_file, R0, LOB_WHICH, value);	// store in $R0low
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_OUT()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_OUT(Controller cc, RegisterFilePtr reg_file)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointers to controller and register file
 =	error conditions:  	null pointers
 =
 =	OUT port#		;IO[port#] <- $R0low; if port is read only results are undefined
 =
 ====================================================================================================*/
int controller_exec_OUT(Controller cc, RegisterFilePtr reg_file)
{
	int err = 0;
	int* error = &err;
	if(cc != NULL && reg_file != NULL)
	{
		uchar value = registerFile_getByteFrom(reg_file, R0, LOB_WHICH, error);  // get byte from $R0low
		err |= io_output(VID, value);	// output to video
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=====================================================================================================
 =   	Comment block for function: controller_exec_HALT()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int controller_exec_OUT(InternalRegisters the_internal)
 =	return value ranges: 	0 (success), NULL_ERR
 =	parameter value ranges: pointer to internal registers
 =	error conditions:  	null pointers
 =
 =	set CPU halt bit to TRUE
 =
 ====================================================================================================*/
int controller_exec_HALT(InternalRegisters the_internal)
{
	int err = 0;
	int* error = &err;
	if(the_internal != NULL)
	{
		err |= internalRegisters_setHalt(the_internal, TRUE);
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 +  CPU ADT implementation
 +
 +  Operations:
 +	Initialize:  creates controller object with initial state set to FETCH and returns a pointer.
 +	Set Halt:  sets halt bit to TRUE
 +	Clear Halt:  sets halt bit to FALSE
 +	Check Halt:  returns halt bit value
 +	Tick:	triggers the simulated cpu cycle.
 +
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*=====================================================================================================
 =   	Comment block for function: cpu_initialize()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		CPU cpu_initialize()
 =	return value ranges: 	pointer to cpu
 =	parameter value ranges: N/A
 =	error conditions:  	N/A
 =
 =	allocates the struct and it's members.
 =
 ====================================================================================================*/
CPU cpu_initialize()
{
	CPU cpu = (CPU) malloc(sizeof(CPUStr));
	cpu->alu = ALU_initialize();
	cpu->controller = controller_initialize();
	cpu->reg_file = registerFile_initialize();
	cpu->internal = internalRegisters_initialize();

	return cpu;
}


/*=====================================================================================================
 =   	Comment block for function: cpu_tick()
 =   	Programmer name:
 =   	Final test and approval date:
 =
 =   	Synopsis:		int cpu_tick(CPU)
 =	return value ranges: 	0 (success), error code
 =	parameter value ranges: pointer to cpu
 =	error conditions:  	null pointer
 =
 =	Steps the controller to the next stage - the return value will be non-zero if there is an error
 =	or the controller sets the CPU halt bit (due to executing a HALT instruction)
 ====================================================================================================*/
int cpu_tick(CPU cpu, Memory mem)
{
	int err = 0;
	int* error = &err;

	if(cpu != NULL)
	{
		err |= controller_step(cpu->controller, cpu->reg_file, cpu->alu, cpu->internal, mem);
	}
	else
	{
		err |= NULL_ERR;
	}

	return err;
}

/*=================================================================================================
 = Comment block for function: registerTest
 = Programmer names: Tony Butterfield, Evan Phillips
 = Final test and approval date: 1/22/11
 = Synopsis:
 =	void registerTest()
 =	Return value ranges: N/A
 =	Parameter value ranges: N/A
 =	Error conditions: N/A
 = Runs test cases for each of the register_ functions.
 ==================================================================================================*/
void registerTest() {
	//register_initialize
	RegisterPtr rp = register_initialize();
	if (rp == NULL)
		printf("register_initialize returned a NULL pointer!\n");
	//register_getLowByte
	Register reg = 0xDDCC;
	rp = &reg;
	int err = 0;
	int *error = &err;
	uchar uchar_result = register_getLowByte(rp, error);
	if (uchar_result != 0xCC)
		printf("register_getLowByte did not return the correct value 0xCC! Value was: %X\n", uchar_result);
	uchar_result = register_getLowByte(NULL, error);
	if (!(((*error & NULL_ERR) == NULL_ERR) && (uchar_result == 0)))
		printf("register_getLowByte retrieved from NULL pointer!");

	//register_getHiByte
	*error = 0;
	uchar_result = register_getHiByte(rp, error);
	if (uchar_result != 0xDD)
		printf("register_getHiByte did not return the correct value 0xDD! Value was: %X\n", uchar_result);
	uchar_result = register_getHiByte(NULL, error);
	if (!(((*error & NULL_ERR) == NULL_ERR) && (uchar_result == 0)))
		printf("register_getHiByte retrieved from NULL pointer!");

	//register_putLowByte
	uchar uchar_temp = 0xAA;
	err |= register_putLowByte(NULL, 0);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("register_putLowByte allowed putting into  NULL pointer!\n");
	err |= register_putLowByte(rp, uchar_temp);
	ushort ushort_result = *rp;
	if ((ushort_result & LOB_MASK) != uchar_temp)
		printf("register_putLowByte put incorrect value in LOB! Expected: 0xAA Actual: %X\n", ushort_result);
	if ((ushort_result & HOB_MASK) != (reg & HOB_MASK))
		printf("register_putLowByte modified value in HOB! Actual: %X\n", ushort_result);

	//register_putHiByte
	err |= register_putHiByte(NULL, 0);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("register_putHiByte allowed putting into NULL pointer!\n");
	uchar_temp = 0xBB;
	err |= register_putHiByte(rp, uchar_temp);
	ushort_result = *rp;
	if ((ushort_result & HOB_MASK) != ((ushort) uchar_temp << 8))
		printf("register_putHiByte put incorrect value in HOB! Expected: 0xBB Actual: %X\n", ushort_result);
	if ((ushort_result & LOB_MASK) != (reg & LOB_MASK))
		printf("register_putHiByte modified value in LOB! Actual: %X\n", ushort_result);

	//register_signOf
	ushort ushort_temp = 1;
	ushort ushort_temp2 = -1;
	RegisterPtr pos = &ushort_temp;
	RegisterPtr neg = &ushort_temp2;
	if (register_signOf(pos) != 0)
		printf("register_signOf did not detect sign of a positive number correctly!\n");
	if (register_signOf(neg) != 1)
		printf("register_signOf did not detect sign of a negative number correctly!\n");
	err |= register_signOf(NULL);
	if(!((err & NULL_ERR) == NULL_ERR))
		printf("register_signOf checked sign of NULL pointer!");

	//register_getRegValue
	*error = 0;
	reg = 42;
	rp = &reg;
	ushort_result = register_getRegValue(rp, error);
	if (ushort_result != reg)
		printf("register_getRegValue did not return correct value! Expected: 42 Actual: %X\n", ushort_result);
	ushort_result = register_getRegValue(NULL, error);
	if (!(((*error & NULL_ERR) == NULL_ERR) && (uchar_result == 0)))
		printf("register_getRegValue retrieved value of a NULL pointer!");

	//register_putRegValue
	err |= register_putRegValue(NULL, 0);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("register_putRegValue allowed putting into NULL pointer!\n");
	ushort_temp = 43;
	err |= register_putRegValue(rp, ushort_temp);
	if (*rp != ushort_temp)
		printf("register_putRegValue put incorrect value! Expected: 42 Actual: %X\n", *rp);
}

/*=================================================================================================
 = Comment block for function: registerFileTest
 = Programmer names: Tony Butterfield, Evan Phillips
 = Final test and approval date: 1/23/11
 = Synopsis:
 =	void registerFileTest()
 =	Return value ranges: N/A
 =	Parameter value ranges: N/A
 =	Error conditions: N/A
 = Tests the registerFile_ functions.
 ==================================================================================================*/
void registerFileTest(void) {
	//registerFile_initialize
	RegisterFilePtr rf = registerFile_initialize();
	if (rf == NULL)
		printf("registerFile_initialize returned a NULL pointer!");

	//registerFile_getByteFrom
	int err = 0;
	int * error = &err;
	uchar uchar_testval = 0xAA;
	uchar uchar_testval2 = 0xBB;
	ushort ushort_testval = 0xBBAA;
	*rf[0] = ushort_testval;
	uchar uchar_result = 0;
	uchar_result = registerFile_getByteFrom(rf, 0, LOB_WHICH, error);
	if (uchar_result != uchar_testval)
		printf("registerFile_getByteFrom LOB did not return correct value! Expected 0xAA Actual: %X", uchar_result);
	uchar_result = registerFile_getByteFrom(rf, 0, HOB_WHICH, error);
	if (uchar_result != uchar_testval2)
		printf("registerFile_getByteFrom HOB did not return correct value! Expected 0xBB Actual: %X", uchar_result);
	uchar_result = registerFile_getByteFrom(NULL, 0, LOB_WHICH, error);
	if ((*error & NULL_ERR) != NULL_ERR)
		printf("registerFile_getByteFrom allowed retrieving from NULL pointer!");
	uchar_result = registerFile_getByteFrom(rf, REGISTER_COUNT + 1, LOB_WHICH, error);
	if ((*error & REG_NOT_FOUND_ERR) != REG_NOT_FOUND_ERR)
		printf("registerFile_getByteFrom allowed retrieving from a register that was out of bounds!");

	//registerFile_putByteTo
	err |= registerFile_putByteTo(rf, 1, LOB_WHICH, uchar_testval);
	if (*rf[1] != uchar_testval)
		printf("registerFile_putByteTo LOB did not set correct value! Expected 0xAA Actual: %X", *rf[1]);
	err |= registerFile_putByteTo(rf, 1, HOB_WHICH, uchar_testval2);
	if (*rf[1] & HOB_MASK != uchar_testval2 << 8)
		printf("registerFile_putByteTo HOB did not set correct value! Expected 0xBB Actual: %X", *rf[1]);
	err |= registerFile_putByteTo(NULL, 1, LOB_WHICH, uchar_testval);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("registerFile_putByteTo allowed setting to a NULL pointer!");
	err |= registerFile_putByteTo(rf, REGISTER_COUNT + 1, LOB_WHICH, uchar_testval);
	if ((err & REG_NOT_FOUND_ERR) != REG_NOT_FOUND_ERR)
		printf("registerFile_putByteTo allowed setting to a register that was out of bounds!");

	//registerFile_getRegVal
	ushort ushort_result = 0;
	ushort ushort_testval2 = 0xDDCC;
	*rf[2] = ushort_testval2;
	ushort_result = registerFile_getRegValue(rf, 2, error);
	if (ushort_result != ushort_testval2)
		printf("registerFile_getRegVal did not return correct value! Expected 0xDDCC Actual: %X", ushort_result);
	ushort_result = registerFile_getRegValue(NULL, 2, error);
	if ((*error & NULL_ERR) != NULL_ERR)
		printf("registerFile_getRegVal allowed retrieving from NULL pointer!");
	ushort_result = registerFile_getRegValue(rf, REGISTER_COUNT + 1, error);
	if ((*error & REG_NOT_FOUND_ERR) != REG_NOT_FOUND_ERR)
		printf("registerFile_getRegVal allowed retrieving from a register that was out of bounds!");

	//registerFile_putRegVal
	err |= registerFile_putRegValue(rf, 3, ushort_testval2);
	if (*rf[3] != ushort_testval2)
		printf("registerFile_putRegValue did not set correct value! Expected: 0xDDCC Actual: ", *rf[3]);
	err |= registerFile_putRegValue(NULL, 3, ushort_testval2);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("registerFile_putRegValue allowed setting to a NULL pointer!");
	err |= registerFile_putRegValue(rf, REGISTER_COUNT + 1, ushort_testval2);
	if ((err & REG_NOT_FOUND_ERR) != REG_NOT_FOUND_ERR)
		printf("registerFile_putRegValue allowed setting to a register that was out of bounds!");
}

/*=================================================================================================
 = 	Comment block for function: memoryTest
 = 	Programmer names: Tony Butterfield, Evan Phillips
 = 	Final test and approval date: 1/24/11
 =
 = 		Synopsis:		void memoryTest()
 =		Return value ranges: 	N/A
 =		Parameter value ranges: N/A
 =		Error conditions: 	N/A
 = 	Tests the Memory Module ADT functions.
 =
 ==================================================================================================*/
void memoryTest()
{
	int err = 0;
	int* error = &err;
	uchar test_byte;
	ushort test_word;


	MemoryModulePtr mm = memory_initialize();			// initialize memory

	// test writing byte to memory.
	err |= memory_storeByteTo(mm, 0x3210, 0xAA);		// write xAA to loc
	if((err & NULL_ERR) == NULL_ERR)
		printf("Test Byte Write: Memory Module failed to initalize\n");
	if((err & NULL_ERR) == ERROR_MEM_OUT_OF_RANGE)
		printf("Test Byte Write: Address out of range.");

	// test reading byte from memory.
	test_byte = memory_fetchByteFrom(mm, 0x3210, error);		// check new value in loc
	if((*error & NULL_ERR) == NULL_ERR)
		printf("Test Byte Read: Memory Module failed to initalize\n");
	if((*error & ERROR_MEM_OUT_OF_RANGE) == ERROR_MEM_OUT_OF_RANGE)
		printf("Test Byte Read: Address out of range.");
	if(test_byte != 0xAA)
		printf("Test Byte Read: Data read from memory does not match data written.");


	// test writing word to memory
	err |= memory_storeWordTo(mm, 0x4321, 0xABCD);		// write xABCD to loc
	if((err & NULL_ERR) == NULL_ERR)
		printf("Test Word Write: Memory Module failed to initalize\n");
	if((err & ERROR_MEM_OUT_OF_RANGE) == ERROR_MEM_OUT_OF_RANGE)
		printf("Test Word Write: Address out of range.");

	test_word = memory_fetchWordFrom(mm, 0x4321, error);		// check new value in loc
	if((*error & NULL_ERR) == NULL_ERR)
		printf("Test Word Read: Memory Module failed to initalize\n");
	if((*error & ERROR_MEM_OUT_OF_RANGE) == ERROR_MEM_OUT_OF_RANGE)
		printf("Test Word Read: Address out of range.");
	if(test_word != 0xABCD)
		printf("Test Word Read: Data read from memory does not match data written.");
}

/*=================================================================================================
 = Comment block for function: ALUTest
 = Programmer names: Tony Butterfield, Evan Phillips
 = Final test and approval date: 2/12/11
 = Synopsis:
 =      void ALUTest()
 =      Return value ranges: N/A
 =      Parameter value ranges: N/A
 =      Error conditions: N/A
 = Tests most functions of the ALU. Some functions are not explicitly tested here because they
 = are tested by manually inspecting the output of the test driver.
 ==================================================================================================*/
void ALUTest() {
	//ALU_initialize()
	ALU a = ALU_initialize();
	if (a == NULL)
		printf("ALU_initialize returned null");
	if (a->A == NULL || a->B == NULL || a->C == NULL)
		printf("ALU_initialze left internal register null");

	//ALU_loadA
	ushort ushort_val = 32;
	int err = 0;
	int * error = &err;
	err |= ALU_loadA(NULL, ushort_val);
	if (err != NULL_ERR)
		printf("ALU_loadA allowed null ALU");
	err |= ALU_loadA(a, ushort_val);
	if (*a->A != ushort_val)
		printf("ALU_loadA loaded incorrect value. Expected: %X Got: %X", ushort_val, *a->A);

	//ALU_loadB
	err |= ALU_loadB(NULL, ushort_val);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_loadB allowed null ALU");
	err |= ALU_loadB(a, ushort_val);
	if (*a->B != ushort_val)
		printf("ALU_loadB loaded incorrect value. Expected: %X Got: %X", ushort_val, *a->B);

	//ALU_selectOperation
	uchar uchar_val = OP_MUL;
	err |= ALU_selectOperation(NULL, uchar_val);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_selectOperation allowed null ALU");
	err |= ALU_selectOperation(a, 0xFF);
	if ((err & OP_OUT_OF_RANGE_ERR) != OP_OUT_OF_RANGE_ERR)
		printf("ALU_selectOperation allowed out of range operation");
	err |= ALU_selectOperation(a, uchar_val);
	if (a->op_sel != uchar_val)
		printf("ALU_selectOperation did not set correct operation. Expected: %X Got: %X", uchar_val, a->op_sel);

	//ALU_readC
	*a->C = ushort_val;
	ushort ushort_result = 0;
	ushort_result = ALU_readC(a, error);
	if (ushort_result != ushort_val)
		printf("ALU_readC returned incorrect value. Expected: %X Got: %X", ushort_val, ushort_result);

	//set up for testing the arithemtic functions
	ushort regA = 20;
	ushort regB = 11;
	ALU_loadA(a, regA);
	ALU_loadB(a, regB);
	RegisterFilePtr rf = registerFile_initialize();
	RegisterPtr sw = register_initialize();

	//ALU_add
	err |= ALU_add(NULL);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_add allowed null parameter");
	err |= ALU_add(a);
	if (*a->C != (regA + regB))
		printf("ALU_add set wrong value. Expected: %X Got: %X", regA + regB, *a->C);

	//ALU_sub
	err |= ALU_sub(NULL);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_sub allowed null parameter");
	err |= ALU_sub(a);
	if (*a->C != (regA - regB))
		printf("ALU_sub set wrong value. Expected: %X Got: %X", regA - regB, *a->C);

	//ALU_mul
	err |= ALU_multiply(NULL, rf);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_multiply allowed null parameter");
	err |= ALU_multiply(a, NULL);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_multiply allowed null parameter");
	err |= ALU_multiply(a, rf);
	int int_result = (*rf[9] << 16) + *rf[8];
	if (int_result != (regA * regB))
		printf("ALU_multiply set wrong value. Expected: %X Got: %X", regA * regB, int_result);

	//ALU_divide
	err |= ALU_divide(NULL, rf);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_divide allowed null parameter");
	err |= ALU_divide(a, NULL);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_divide allowed null parameter");
	err |= ALU_divide(a, rf);
	ushort_result = *rf[0xA];
	if (ushort_result != (ushort)(regA / regB))
		printf("ALU_divide set wrong value. Expected: %X Got: %X", regA / regB, ushort_result);
	ushort remainder = *rf[0xB];
	if (remainder != regA % regB)
		printf("ALU_divide set wrong remainder. Expected: %X Got: %X", regA % regB, remainder);

	//ALU_negate
	err |= ALU_negate(NULL);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_negate allowed null parameter");
	err |= ALU_negate(a);
	if (*a->C != (ushort)-regA)
		printf("ALU_negate set wrong value. Expected: %X Got: %X", -regA, *a->C);

	//ALU_and
	err |= ALU_and(NULL);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_and allowed null parameter");
	err |= ALU_and(a);
	if (*a->C != (regA & regB))
		printf("ALU_and set wrong value. Expected: %X Got: %X", regA & regB, *a->C);

	//ALU_or
	err |= ALU_or(NULL);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_or allowed null parameter");
	err |= ALU_or(a);
	if (*a->C != (regA | regB))
		printf("ALU_or set wrong value. Expected: %X Got: %X", regA | regB, *a->C);

	//ALU_xor
	err |= ALU_xor(NULL);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_xor allowed null parameter");
	err |= ALU_xor(a);
	if (*a->C != (regA ^ regB))
		printf("ALU_xor set wrong value. Expected: %X Got: %X", regA ^ regB, *a->C);

	//ALU_not
	err |= ALU_not(NULL);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_not allowed null parameter");
	err |= ALU_not(a);
	if (*a->C != (ushort)~regA)
		printf("ALU_not set wrong value. Expected: %X Got: %X", ~regA, *a->C);

	//ALU_shiftLeft
	err |= ALU_shiftLeft(NULL);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_shiftLeft allowed null parameter");
	err |= ALU_shiftLeft(a);
	if (*a->C != (regA << 1))
		printf("ALU_shiftLeft set wrong value. Expected: %X Got: %X", regA << 1, *a->C);

	//ALU_shiftRight
	err |= ALU_shiftRight(NULL);
	if ((err & NULL_ERR) != NULL_ERR)
		printf("ALU_shiftRight allowed null parameter");
	err |= ALU_shiftRight(a);
	if (*a->C != (regA >> 1))
		printf("ALU_shiftRight set wrong value. Expected: %X Got: %X", regA >> 1, *a->C);

}

/*=================================================================================================
 =      Comment block for function: display_registerFile()
 =      Programmer names: Tony Butterfield, Evan Phillips
 =      Final test and approval date: 1/24/11
 =
 =              Synopsis:               int display_registerFile(RegisterFilePtr)
 =              Return value ranges:    0 (success), NULL_ERR
 =              Parameter value ranges: pointer to Register File
 =              Error conditions:       null pointer
 =
 =      Displays a snapshot of the register file.
 =
 ==================================================================================================*/
int display_registerFile(RegisterFilePtr rf)
{
        int err = 0;
        int* error = &err;

        int i;
        if (rf == NULL) {
                err = NULL_ERR;
                return;
        }
        printf("\nSnapshot of Register File:\n");
        for(i = 0; i < REGISTER_COUNT/2; i++)
        {
                printf("     $R%X:  0x%04X     $R%X:  0x%04X\n",
                        i, registerFile_getRegValue(rf, i, error), i + (REGISTER_COUNT / 2),
                        registerFile_getRegValue(rf, i + (REGISTER_COUNT / 2), error));
        }
        return err;
}

/*=================================================================================================
 =      Comment block for function: display_memoryBlock()
 =      Programmer names: Tony Butterfield, Evan Phillips
 =      Final test and approval date: 1/24/11
 =
 =              Synopsis:               void display_memoryBlock()
 =              Return value ranges:    N/A
 =              Parameter value ranges: MemoryModulePtr, int, int, int*
 =              Error conditions:       N/A
 =
 =      Displays a snapshot of a block of memory.
 =
 ==================================================================================================*/
void display_memoryBlock(MemoryModulePtr mm, int add_first, int add_last, int* error)
{
        int i;
        if (mm == NULL) {
                *error = NULL_ERR;
                return;
        }
        if ((add_first < MEM_FIRST || add_first >= MEM_LAST) || (add_last <= MEM_FIRST || add_last >= MEM_LAST || add_last < add_first)) {
                *error = ERROR_MEM_OUT_OF_RANGE;
                return;
        }
        printf("\nSnapshot of memory block from x%X through x%X\n", add_first, add_last);

        for(i = add_first; i <= add_last; i++)
        {
                printf("    %04X:  %02X\n", i, memory_fetchByteFrom(mm, i, error));
        }
}

/*=================================================================================================
 = Comment block for function: nextInstruction()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      void load(CPU, Memory)
 =      Return value ranges: ushort
 =      Parameter value ranges: pointer to FILE
 =      Error conditions: N/a
 =
 = 	parses next instruction from the file.
 ==================================================================================================*/
ushort nextInstruction(FILE * file) {
	if(file == NULL || feof(file)) return 0;
	char* line1 = (char*) malloc(sizeof(char) * 6);	//char * 4 because fgets includes newline
	char* line2 = (char*) malloc(sizeof(char) * 6);

	fgets(line1, 6, file);
	fgets(line2, 6, file);

	uchar lo_byte = (uchar) strtoul(line1, NULL, 16);
	uchar hi_byte = (uchar) strtoul(line2, NULL, 16);

	// --- debug ---
	//printf("\nEcho result from first fgets(): %02X\n", lo_byte);
	//printf("Echo result from second fgets(): %02X\n", hi_byte);
	// --- debug ---

	ushort result = (hi_byte << 8) + lo_byte;

	// --- debug ---
	//printf("Echo result from nextInstruction(): %04X\n", result);
	// --- debug ---

	return result;
}

/*=================================================================================================
 = Comment block for function: loadMem()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      ushort loadMem(CPU, Memory, FILE*)
 =      Return value ranges: pointer to FILE
 =      Parameter value ranges: pointers to CPU, Memory Module, and FILE
 =      Error conditions: 0 for success, 1 for failure
 =
 = 	loads instructions into memory starting at 0x3000
 ==================================================================================================*/
ushort loadMem(CPU cpu, Memory mem, FILE * file) {
	ushort returnval = 0;
	if(cpu != NULL && mem != NULL && file != NULL) {
		int count = MEM_FIRST;
		int err = 0;
		ushort word = 1;
		err |= internalRegisters_setPC(cpu->internal, MEM_FIRST);
		while (count < MEM_LAST && word != EOF) {
		    word = nextInstruction(file);
			err = memory_storeWordTo(mem, count, word);
			if(err) {
				printf("Error while loading program to memory, skipping.");
				break;
			}
			count += 2;
		}
		if(!err)
			returnval = 1;
	}
	return returnval;
}

/*=================================================================================================
 = Comment block for function: load()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      void load(CPU, Memory)
 =      Return value ranges: pointer to FILE
 =      Parameter value ranges: pointers to CPU, and Memory Module
 =      Error conditions: N/a
 =
 = 	prompts for and loads a hex code program.
 ==================================================================================================*/
FILE * load(CPU cpu, Memory mem) {
	char * temp = (char *) malloc(sizeof(char) * 26);
	printf("Please enter a file name (maximum 24 characters): ");
	scanf("%24s", temp);
	//temp[25] = '\0';
	FILE * file = fopen(temp, "r");
	if (file != NULL) {
		loadMem(cpu, mem, file);
		printf("\n%s loaded.\n", temp);
	}
	else
		printf("Specified file not found!");
	return file;
}

/*=================================================================================================
 = Comment block for function: run()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      void run(CPU, Memory)
 =      Return value ranges: void
 =      Parameter value ranges: pointers to CPU, and Memory Module
 =      Error conditions: N/a
 =
 = 	runs the simulation until it detects a non-zero return value (error or halt)
 ==================================================================================================*/
void run(CPU cpu, Memory mem) {
	int error = internalRegisters_setHalt(cpu->internal, FALSE);
	while(!internalRegisters_checkHalt(cpu->internal, &error)) {
		error |= internalRegisters_setHalt(cpu->internal, cpu_tick(cpu, mem));
	}
	printf("\nHalt bit was set and the program ended.\n");
}

/*=================================================================================================
 = Comment block for function: step()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      void step(CPU, Memory)
 =      Return value ranges: void
 =      Parameter value ranges: pointers to CPU, and Memory Module
 =      Error conditions: N/a
 =
 = 	advances simulation one step
 ==================================================================================================*/
void step(CPU cpu, Memory mem) {
    int error = 0;
    printf("PC: X%X\n", internalRegisters_getPC(cpu->internal, &error));
    printf("IR: X%X\n", internalRegisters_getIR(cpu->internal, &error));
    printf("SW: X%X\n", internalRegisters_getSW(cpu->internal, &error));
    printf("Error: %d\n", error);
	cpu_tick(cpu, mem);
}

/*=================================================================================================
 = Comment block for function: displayMenu()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      FILE * displayMenu(CPU, Memory, FILE*)
 =      Return value ranges: Pointer to FILE
 =      Parameter value ranges: pointers to CPU, Memory Module, and FILE
 =      Error conditions: N/a
 =
 =
 ==================================================================================================*/
FILE * displayMenu(CPU cpu, Memory mem, FILE * file) {
	printf("Select: 1) Load File, 2) Run, 3) Step, 4) Display Registers, 5) Display Memory, 6) Quit: ");
	char temp[2];
	int error = 0;
	int * err = &error;
	scanf("%1s", temp);
	temp[1] = '\0';
	int tempint = atoi(temp);
	unsigned int start = 0x3000;
	int end = 0x3000 + 16;
	switch(tempint) {
		case 1:
			file = load(cpu, mem);
			break;
		case 2:
			run(cpu, mem);
			break;
		case 3:
			step(cpu, mem);
			break;
		case 4:
			display_registerFile(cpu->reg_file);
			break;
		case 5:
			printf("What memory address to start at (ex. 0X3000): ");
			scanf("%6X", &start);
			printf("How many bytes after the starting address should be shown: ");
			scanf("%3d", &end);
			end = start + end;
			display_memoryBlock(mem, start, end, err);
			break;
		case 6:
			exit(0);
			break;
		default:
			printf("Incorrect selection. Please try again.");
			file = displayMenu(cpu, mem, file);
			break;
	}
	return file;
}

/*=================================================================================================
 = Comment block for function: main()
 = Programmer names:
 = Final test and approval date:
 = Synopsis:
 =      RegisterPtr maint()
 =      Return value ranges: 0 on success, else integer error value
 =      Parameter value ranges: N/a
 =      Error conditions: N/a
 =
 = 	Dummy main function
 ==================================================================================================*/
int main(int argc, char * argv[]) {
	short running = 1;
	short needMenu = 0;
	FILE * file = NULL;//have to be careful about this
	CPU cpu = cpu_initialize();
	Memory mem = memory_initialize();
	while (running) {
		if(argc > 2 && strcmp(argv[1], "-p") == 0 && needMenu == 0) {
			file = fopen(argv[2], "r");
			if(file == NULL) {
				printf("File specified in command line was not found!");
			}
			else {}
				loadMem(cpu, mem, file);
				if(argc > 3 && strcmp(argv[3], "-s") == 0)
					step(cpu, mem);
			needMenu = 1;
		}
		else
			file = displayMenu(cpu, mem, file);
	}
}
